/*
* Copyright (c) 2016 . All Rights Reserved.
*/
package com.cgmnx.admin.common.random;

import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource;
import org.apache.commons.lang3.RandomStringUtils;

import java.io.IOException;
import java.security.SecureRandom;


public class SecureRandomNumberGenerator implements RandomNumberGenerator {

    protected static final int DEFAULT_NEXT_BYTES_SIZE = 16; //16 bytes == 128 bits (a common number in crypto)

    private int defaultNextBytesSize;
    private SecureRandom secureRandom;

    public SecureRandomNumberGenerator() {
        this.defaultNextBytesSize = DEFAULT_NEXT_BYTES_SIZE;
        this.secureRandom = new SecureRandom();
    }

    public static void main(String[] args) throws IOException {

        SecureRandomNumberGenerator generator = new SecureRandomNumberGenerator();

        generator.setSeed(RandomStringUtils.randomAlphanumeric(64).getBytes());

        System.out.println(generator.nextString(78).toString());
        System.out.println(RandomStringUtils.randomAlphanumeric(64));
    }

    public void setSeed(byte[] bytes) {
        this.secureRandom.setSeed(bytes);
    }

    public SecureRandom getSecureRandom() {
        return secureRandom;
    }

    public void setSecureRandom(SecureRandom random) throws NullPointerException {
        if (random == null) {
            throw new NullPointerException("SecureRandom argument cannot be null.");
        }
        this.secureRandom = random;
    }

    public int getDefaultNextBytesSize() {
        return defaultNextBytesSize;
    }

    public void setDefaultNextBytesSize(int defaultNextBytesSize) throws IllegalArgumentException {
        if (defaultNextBytesSize <= 0) {
            throw new IllegalArgumentException("size value must be a positive integer (1 or larger)");
        }
        this.defaultNextBytesSize = defaultNextBytesSize;
    }

    public ByteSource nextBytes() {
        return nextBytes(getDefaultNextBytesSize());
    }

    public ByteSource nextBytes(int numBytes) {
        if (numBytes <= 0) {
            throw new IllegalArgumentException("numBytes argument must be a positive integer (1 or larger)");
        }
        byte[] bytes = new byte[numBytes];
        this.secureRandom.nextBytes(bytes);
        return ByteSource.wrap(bytes);
    }

    public String nextString(int numBytes) {

        ByteSource byteSource = nextBytes(numBytes);
        try {
            return byteSource.hash(Hashing.md5()).toString();
        } catch (IOException e) {
            return Hashing.md5().newHasher().hash().toString();
        }
    }

}